package com.example.mq.mqserver.core;

import lombok.Data;

import java.io.Serializable;
import java.util.UUID;

// 该类表示一个要传递的消息
// Message 对象既要能在网络上传输, 也要能够写入文件
// 此处需要对 Message 进行序列化和反序列化操作
// (此处使用 标准库 自带的序列化/反序列化操作, Json提供的操作不支持二进制数据)
@Data
public class Message implements Serializable {
    private static final long serialVersionUID = 1L; //用来验证版本
    // basicProperties {messageId, routingKey, deliverMode}, body

    // 消息属性
    private BasicProperties basicProperties = new BasicProperties();
    // 消息正文
    private byte[] body;

    // 辅助属性 - 用于持久化存储
    // Message 的持久化存储到文件中
    // 一个文件可能会存储多条消息
    // 使用两个偏移量来描述消息在文件中的位置  [offsetBeg, offsetEnd).
    // 这俩属性并不需要被序列号保存到文件中, 消息一旦被写入文件, 位置就固定了. 不需要再单独保存
    // 这俩属性描述的目的, 是为了让内存中的 Mesage 对象, 能够快速找到对应硬盘上的 Message 的位置
    private transient long offsetBeg = 0; // 消息数据的开头位置距离文件开头的位置偏移(字节)
    private transient long offsetEnd = 0; // 消息数据的结尾位置距离文件开头的位置偏移(字节)
    // 表示该消息在文件中是否是有效消息(针对逻辑删除)
    // 0x1-有效, 0x0-无效
    private byte isValid = 0x1;

    // 创建工厂方法, 让工厂方法封装, 创建 Message 的过程
    // 该方法可以自动生成 唯一的 MessageId.
    // 如果 routingKey 和 basicProperties 已存在, 以新的的为主
    public static Message createMessageWithId(String routingKey, BasicProperties basicProperties, byte[] body) {
        Message message = new Message(basicProperties, body);
        // 此处生成的 MessageId 以 M- 作为前缀 (为了和其他的 id 做出区分)
        message.setMessageId("M-" + UUID.randomUUID());
        message.setRoutingKey(routingKey);
        return message;

        // offsetBeg, offsetEnd, isValid 是消息持久化的内容
        // 在消息写入文件时会进行设定
        // 此处只是在内存中创建一个 Message 对象, 不涉及持久化
    }

    public Message(BasicProperties basicProperties, byte[] body) {
        if(basicProperties != null) this.basicProperties = basicProperties;
        this.body = body;
    }

    public Message() {
    }

    public String getMessageId() {
        return basicProperties.getMessageId();
    }

    public void setMessageId(String messageId) {
        basicProperties.setMessageId(messageId);
    }

    public String getRoutingKey() {
        return basicProperties.getRoutingKey();
    }

    public void setRoutingKey(String routingKey) {
        basicProperties.setRoutingKey(routingKey);
    }

    public int getDeliverMode() {
        return basicProperties.getDeliverMode();
    }

    public void setDeliverMode(int deliverMode) {
        basicProperties.setDeliverMode(deliverMode);
    }
}
